#include "stdafx.h"

#include "Point.h"
#include "BorderTracing.h"

#include <math.h>

inline unsigned int ChainCode::GetX(unsigned int x, unsigned char dir)
{
	unsigned new_dir;

	switch (dir)
	{
	case 1:
	case 0:
	case 7:
		new_dir = +1;
		break;
	case 2:
	case 6:
		new_dir = 0;
		break;
	case 3:
	case 4:
	case 5:
		new_dir = -1;
		break;
	}

	return x + new_dir;
}

inline unsigned int ChainCode::GetY(unsigned int y, unsigned char dir)
{
	unsigned new_dir;

	switch (dir)
	{
	case 1:
	case 2:
	case 3:
		new_dir = +1;
		break;
	case 0:
	case 4:
		new_dir = 0;
		break;
	case 5:
	case 6:
	case 7:
		new_dir = -1;
		break;
	}

	return y + new_dir;
}

void ChainCode::Extract(unsigned int dwHeight, 
								unsigned int dwWidth, 
								unsigned int w, 
								BYTE* lpSrc,
								list<struct stChainCode>& l)
{
	unsigned int i, j;

	//Point p0;
	Point p1;
	Point pc;
	Point pt;

	bool first, finished;

	unsigned char dir, next_dir;
	unsigned char colors[COLORS];

	// clear colors vector
	memset(colors, NULL, sizeof(colors));

	ChainCode chainCode;

	for (i = 0; i < dwHeight; i++)
	{
		for (j = 0; j < dwWidth; j++)
		{
				if ((lpSrc[i*w + j] != WHITE) && (colors[lpSrc[i*w + j]] == 0) )  
				{
					chainCode.chain.clear();
					// found object pixel
					// begin border tracing
					chainCode.p.x = j;
					chainCode.p.y = i;
					chainCode.c = lpSrc[i*w + j]; // object color

					colors[chainCode.c] = 1;

					dir = 7;

					// the next pixel is first pixel
					first = true;

					finished = false;

					// init curent pixel
					pc = chainCode.p;

					// draw first pixel
					// lpDst[pc.y * w + pc.x] = p0c;
					while (!finished)
					{
						// compute next direction
						if (dir % 2 == 0)
						{
							next_dir = (dir + 7) % 8;
						}
						else
						{
							next_dir = (dir + 6) % 8;
						}

						// search for next pixel object
						// for ( ;next_dir <= 8; next_dir++)
						for (int k = 0; k < 8;  k++)
						{
							pt.x = GetX(pc.x, (next_dir + k) % 8);
							pt.y = GetY(pc.y, (next_dir + k) % 8);

							// assure that we are in image
							if (pt.y >= dwHeight || pt.y < 0)
							{
								continue;
							}

							if (pt.x >= dwWidth || pt.x < 0)
							{
								continue;
							}

							// we found pixel object on the border
							if (lpSrc[pt.y * w + pt.x] == chainCode.c)
							{
								// save second pixel
								if (first)
								{
									first = false;
									p1 = pt;
								}
								else
								{
									// if p0 equals current
									if ((chainCode.p == pc) && (p1 == pt))
									{
										finished = true;
										l.push_back(chainCode);
									}
								}

								dir = (next_dir + k) % 8;

								pc = pt;
								
								// draw border pixel in object color
								// lpDst[pc.y * w + pc.x] = p0c;
	
								// append direction
								chainCode.chain.push_back(dir);

								break;
							}
						}
					}
				}

			}
	}

}